﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Koossery.MVCwin.Filters.basefilter;
using Koossery.MVCwin.Filters.itf;
using Koossery.MVCwin.Properties;
using Koossery.MVCwin.Controller.itf;
using Koossery.MVCwin.Actions.impl;

namespace Koossery.MVCwin.Filters.impl
{
    /// <author>Mohamadou Yacoubou</author>
    /// <summary>
    /// Base implementation of the Exception filter attribute. It's executed after any other filter
    /// </summary>
	public class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter
	{
        private Type exceptionType = typeof(Exception);
        public bool ExceptionHandled { get; set; }
		#region Public Properties
        /// <summary>
        /// The type of exception to handle
        /// </summary>
		public Type ExceptionType
		{
            get
            {
                return exceptionType;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (!typeof(Exception).IsAssignableFrom(value))
                {
                    throw new ArgumentException(String.Format(Resources.IncorrectExceptionTypeException, value.FullName));
                }

                exceptionType = value;
            }
		}

		#endregion Public Properties

		#region Public Methods
        /// <summary>
        /// The method is executed after all other filters. It handle exceptions
        /// </summary>
        /// <param name="filterContext">The context of execution</param>
		public virtual void OnException(Koossery.MVCwin.Filters.context.ExceptionContext filterContext)
		{
            //Avoid null filter context
            if (filterContext == null)
            {
                throw new ArgumentNullException(Resources.ArgumentNullException);
            }
            
            //Retrieve the caught exception
            Exception exception = filterContext.Exception;

            //check the type
            if (!ExceptionType.IsInstanceOfType(exception))
            {
                return;
            }            

            //Check if the controller type is correct
            if (ControllerType != null)
            {                
                filterContext.Result = new RedirectToActionResult(ControllerType.Name, this.ActionName);
            }
            else
            {
                if (this.ViewName != null)
                {
                    filterContext.Result = new ViewResult(this.ViewName);
                }
                else throw new Exception(Resources.ArgumentMissingException);
            }
            filterContext.ExceptionHandled = this.ExceptionHandled;      
		}
		#endregion Public Methods
	}
}